/*
 * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _CONTRACT_H_
#define _CONTRACT_H_

#include <string.h>
#include <time.h>
#include "ql_type.h"
#include "log.h"
#include "json.h"
#include "ql_error_type.h"
#include "account.h"
#include "utils.h"

#define ARG_NUMERIC_LEN         (32) /*abi need bytes len*/
#define ARG_HEXSTRING_LEN       (64)/*A 32bytes number takes 64bytes to represent as a string*/
#define ADDR_ZERO_LONG          "0x0000000000000000000000000000000000000000\0"
#define ADDR_ZERO               "0x0\0"

// constract
#define CONTRACT_SUCCESS                     (ERR_CONTRACT_BASE + 0)
#define CONTRACT_ERR_PARAM_INVALID          -(ERR_CONTRACT_BASE + 1)
#define CONTRACT_ERR_CONTRACT_OPEN          -(ERR_CONTRACT_BASE + 2)
#define CONTRACT_ERR_LARGER_THAN_512KB      -(ERR_CONTRACT_BASE + 3)
#define CONTRACT_ERR_ALLOC_MEMORY           -(ERR_CONTRACT_BASE + 4)
#define CONTRACT_ERR_CONTRACT_READ          -(ERR_CONTRACT_BASE + 5)
#define CONTRACT_ERR_OVER_MAX_SIZE          -(ERR_CONTRACT_BASE + 5)

// response
#define RESPONSE_SUCCESS                 (ERR_RESPONSE_BASE + 0)
#define RESPONSE_ERR_PARAM_INVALID      -(ERR_RESPONSE_BASE + 1)
#define RESPONSE_ERR_ALLOC_MEM          -(ERR_RESPONSE_BASE + 2)
#define RESPONSE_ERR_OVERFLOW           -(ERR_RESPONSE_BASE + 3)

//---------------------------------------------contract-------------------------------------------//

//For arguments, header pointer, H->len is the number of arguments and  H->val is meaningless
typedef ql_strings_t  arg_t;
typedef ql_err_t contract_err_t;

//operation of contract
typedef enum OPCODE_TYPE {
    QL_NONE = 0,
    QL_UPDATE = 1,
    QL_FREEZE = 2,
    QL_UNFREEZE = 3,
    QL_DESTROY = 5,
} OPCODE_TYPE;

//vm type
typedef enum VM_TYPE {
    HVM,
    EVM,
    BVM,
} VM_TYPE;

//contract data struct
typedef struct {
    ql_byte_t   from[43];         // string format.
    ql_byte_t   to[43];           // string format.contract address
    ql_int32_t  value;            // int format.
    ql_byte_t* 	payload;          //content of contract 
    ql_int64_t  timestamp;        // int format.
    ql_int64_t  nonce;            // int format.
	OPCODE_TYPE opcode;
    ql_byte_t*  extra;
    VM_TYPE     vmtype;           //HVM EVM BVM ,the default is EVM
	ql_byte_t*  version;          //The default version = "2.5"
	ql_byte_t*  extraid;         
	ql_byte_t*  contractname;     //default is ""
	ql_byte_t   simulate[6];       //"false" or "true"
    ql_byte_t   signature[133];    // string format.Result of a digital hash signature for a transaction.
}contract_t;

//in abi struct, type can be "function", "construct", "fallback" or "event"
typedef enum ABI_TYPE{
    ABI_FUNCTION,
    ABI_CONSTRUCTOR,
    ABI_FALLBACK,
    ABI_EVENT,
}ABI_TYPE;

//the type of inputs/outputs in abi can be static or dynamic
typedef enum PARAM_TYPE{
    ABI_STATIC = 0,
    ABI_DYNAMIC,
}PARAM_TYPE;

//inputs or outputs struct
typedef struct {
    ql_byte_t*  name;
    ql_byte_t*  paramType;
    ql_byte_t*  components;
    ql_byte_t   indexed[6];//event   
    struct param_t* next;//The list order is the parameter order
}param_t;



//abi struct
typedef struct {
    ABI_TYPE    type;//the default "function"
    ql_byte_t*  name;
    param_t*    inputs;
    param_t*    outputs;
    ql_byte_t   payable[6];
    ql_byte_t   stateMutability[11];//pure,view,nonpayable,payable
    ql_byte_t   constant[6];
    ql_byte_t   anonymous[6];
    struct abi_t *next;
}abi_t;


//---------------------------------------------response-------------------------------------------//
typedef ql_err_t response_err_t;

typedef ql_strings_t topic_t;

//Structure of log related information
typedef struct {
    ql_byte_t addr[43];
    topic_t* topics;
    ql_byte_t* data;
    ql_int64_t blockNumber;
    ql_byte_t* blockHash;
    ql_byte_t* txHash;
    ql_int32_t txIndex;
    ql_int32_t index;
    struct eventlog_t *next;
}eventlog_t;

//Transaction receipt related structures
typedef struct {
    eventlog_t* log;
    // ql_byte_t*  result;//If the value is NULL, the value below is meaningless otherwise (because the result returned may only be a 0x string).

    ql_byte_t   conAddr[43];
    ql_byte_t*  ret;
    ql_byte_t*  txHash;
    ql_byte_t*  vmType;
    ql_int64_t  gasUsed;
    ql_byte_t*  version;
    //valid
    //errorMsg
}ReceiptResponse_t;

//When translating RET back to output, specify the corresponding approximate type (convenient for printf)
typedef enum DECODE_BASICTYPE {
    NO_TYPE = 0,
    INT_VAL,
    UINT_VAL,
    DEC_STRING,
    DEC_BYTES,
}DECODE_BASICTYPE;

//The result of decoding RET
typedef struct {
    ql_byte_t*          bytes;//If type is int or uint, the mandatory type is int64* or uint64*
    // ql_uint64_t*        uintarray;
    // ql_int64_t*         intarray;
    ql_size_t           len;
    DECODE_BASICTYPE    type;
    struct decode_t*    next;
}decode_t;


//------------------------alloc and free mem--------------------//
arg_t* CreateArg();//alloc mem and init it
abi_t* CreateAbi();//alloc mem and init it
void AbiFree(abi_t* abi);
void ArgFree(arg_t *arg);

void CleanContract(contract_t *con);//clean the content in contract, it means free the mem in con, but not free con

//------------------------Add contract invocation (or deployment) parameter correlation----------------------//
/*AddBytesArg: adds bytes arguments, whether dynamic or not, for bytes, string, bytes[].
** Input: val, the bytes numeric argument to add;
** len, the number of arguments to add, i.e. the length of the byte array; (Although the length of a dynamic array is uncertain, the length can be calculated by calling this function.)
** Output: args, list of parameters to modify, add parameters to the list;
** Return value: args or val==NULL Returns the parameter error CONTRACT_ERR_PARAM_INVALID
** Returns successful CONTRACT_SUCCESS*/
contract_err_t AddBytesArg(arg_t* const args, ql_byte_t* val, ql_size_t len);

/*AddUnsignedArrayArg adds an unsigned integer array. And the addition is encoded in the length 64-bit hexadecimal format string format, which is consistent with the ABI call parameter encoding
Void *, which means that the array can be of any type, uin8, 16, 32, 64,
** arraylen, array length
** size, the number of bytes for each element in the array, can be passed in as sizeof(val[0])
** Output: args, which converts the integer array value to a hexadecimal string format and adds it to the end of the argument list
** Return value: If there is an error, return parameter error or memory allocation failure error
** Returns CONTRACT_SUCCESS successfully*/
contract_err_t AddUnsignedArrayArg(arg_t* const args, ql_void_t* val, ql_size_t arraylen, ql_size_t size);

/*AddSignedArrayArg, add a signed integer array as a parameter. Parameter Description The same as AddUnsignedArrayArg*/
contract_err_t AddSignedArrayArg(arg_t* const args, ql_void_t* val, ql_size_t arraylen, ql_size_t size);

/*AddIntArg adds the signed integer to the parameter list. The add format is a 64-bit hexadecimal format string encoding
** Input: val, the integer value to add
** Output: args, list of parameters to be added
** Return value: Returns an error in passing a parameter or memory allocation failure
** Returns CONTRACT_SUCCESS on success*/
contract_err_t AddIntArg(arg_t* const args, ql_int64_t val);

/*AddUintArg, add the unsigned integer to the parameter list. Same instructions as AddIntArg*/
contract_err_t AddUintArg(arg_t* const args, ql_uint64_t val);

//---------------------------------Abi structures are related to their decoding---------------------------------//
//----------Abi constructs generate correlation---------//
/*AbiInitFromString = abiroot AbiInitFromString = abiroot AbiInitFromString = abiroot
** Input: STR, the string to be parsed
** Output: abiroot, generated ABI structure node
** Return value: return parameter error, read file too large, memory allocation failure, or success.*/
contract_err_t AbiInitFromString(abi_t* const abiroot, ql_byte_t *str);

//-------Abi lookup correlation
contract_err_t GetFunc(abi_t* const abiroot, ql_byte_t* const methodName, abi_t* const res);

//----Function selector encoding/decoding----//
/*GetFuncInput: in the ABI structure, obtain a list of inputs related to this function according to methodName, marked with '('. Others similar to getFuncInputWithoutType*/
contract_err_t GetFuncInput(abi_t* const abiroot, ql_byte_t* const methodName, param_t* const res);

contract_err_t GetFuncOutput(abi_t* abiroot, ql_byte_t* methodName, param_t* res);


//----------------------------------Contract related---------------------------------------//
//--------init--------//
/*SetVmtype, set the type of VM in the CON structure.
** Input: VM type to be set
** Output: structure pointer to be modified con;
** Return value: con==NULL Returns the parameter error CONTRACT_ERR_PARAM_INVALID
** Returns successful CONTRACT_SUCCESS*/
contract_err_t SetVMtype(contract_t* const con, const VM_TYPE type);

/*SetContractName sets the contract name in the CON structure.
** Input: the contractName to set, contractName, or NULL if NULL
** Output: structure pointer to be modified con;
** Return value: con==NULL Returns the parameter error CONTRACT_ERR_PARAM_INVALID
** Returns successful CONTRACT_SUCCESS*/
contract_err_t SetContractName(contract_t* const con, const ql_byte_t *const contractName);

//Set the signature of the contract, which is usually the last step in the encapsulation of the contract
contract_err_t SetSignature(contract_t* const con, account_t acc);

/*SetTo, set the target address in the CON structure.
** Input: the address from which to set; It can be NULL, which defaults to 0
** Storage information ex and exID The value can be NULL
** output: structure pointer to initialize con;
** Return value: con==NULL Returns the parameter error CONTRACT_ERR_PARAM_INVALID
** Returns successful CONTRACT_SUCCESS*/
contract_err_t ContractInit(contract_t* const con, const ql_byte_t* const from, const ql_byte_t *const ex, const ql_byte_t *const exid);

//----------------Deployment calls freeze destroy, etc------------//
//Use bin to deploy the contract and set payload
contract_err_t DeployEvmWithoutParam(contract_t* const con, ql_byte_t *payLoad);

contract_err_t DeployEvmWithParam(contract_t* const con, abi_t *abiroot, ql_byte_t *partOfpayLoad, arg_t *args);

//Set the payload of the call contract. Args can be NULL, that is, call with no parameters
contract_err_t InvokeEVM(contract_t* const con, ql_byte_t* const conAddr, ql_byte_t* const methodName, abi_t* const abi, arg_t* const args);

contract_err_t ConUpdate(contract_t* const con, ql_byte_t *conAddress, ql_byte_t *payload);

contract_err_t ConFreeze(contract_t* const con, ql_byte_t *conAddress);

contract_err_t ConUnfreeze(contract_t* const con, ql_byte_t *conAddress);

contract_err_t ConDestroy(contract_t* const con, ql_byte_t *conAddress);

//---------------------------------------------response-------------------------------------------//

//Initialize the ReceiptInit structure
void ReceiptInit(ReceiptResponse_t * const receipt);

//Release the contents of the receipt, not the receipt itself
void CleanReceipt(ReceiptResponse_t * const receipt);

/*ReceiptFromJson, initializes the transaction receipt structure through the CJSON structure.
** Input: items, cJSON structure related to transaction receipt
** Output: the resulting transaction receipt structure
** return RESPONSE_SUCCESS,
** Parameter error returns RESPONSE_ERR_PARAM_INVALID*/
response_err_t ReceiptFromJson(ReceiptResponse_t *const receipt, cJSON *result);

/*According to abiroot structure information, function name, RET string, decoded to obtain res structure. Call the decodeFromParam
** Input: abiroot, abi structure information, to find the corresponding function information from the ABI structure
** methodName, the function name, decodes the output of the function name
** ret, the string to decode
** Output: res, decoding result
** return RESPONSE_SUCCESS,
** Parameter error returns RESPONSE_ERR_PARAM_INVALID
** RESPONSE_ERR_OVERFLOW, overflow when decoding values*/
response_err_t DecodeRet(const abi_t* const abiroot, const ql_byte_t*const methodName, const ql_byte_t*const ret, decode_t*const res);

decode_t* CreateDecodeT();

void DecodeTFree(decode_t *in);
#endif 

